package lastmpd;

/*
 * Copyright (C) 2010 Mark Breddemann
 * 
 * This program is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software Foundation;
 * either version 3 of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this
 * program; if not, see <http://www.gnu.org/licenses/>.
 */

import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bff.javampd.MPD;
import org.bff.javampd.MPDDatabase;
import org.bff.javampd.exception.MPDConnectionException;
import org.bff.javampd.exception.MPDDatabaseException;
import org.bff.javampd.exception.MPDPlaylistException;
import org.bff.javampd.objects.MPDArtist;
import org.bff.javampd.objects.MPDSong;

public class MpdConnection {

	private final Log log = LogFactory.getLog(this.getClass());
	private final String mpdHost;
	private final int mpdPort;
	private final String mpdPassword;
	private final MPD mpd;
	private final MPDDatabase mpdDatabase;
	
	public MpdConnection(String mpdHost, int mpdPort, String mpdPassword) throws MpdException {
		this.mpdHost = mpdHost;
		this.mpdPort = mpdPort;
		this.mpdPassword = mpdPassword;
		
		log.debug("mpdHost=" + mpdHost);
		log.debug("mpdPort=" + mpdPort);
		log.debug("mpdPassword=" + mpdPassword);
		
		try {
			log.debug("connecting to mpd..");
			if (mpdPassword.equals("")) {
				mpd = new MPD(mpdHost, mpdPort);
			} else {
				mpd = new MPD(mpdHost, mpdPort, mpdPassword);
			}
			log.trace("connection established");
			mpdDatabase = mpd.getMPDDatabase();
		} catch (UnknownHostException e) {
			log.error("connection failed: UnknownHostException: " + e.getMessage());
			throw new MpdException(e.getMessage(), e);
		} catch (MPDConnectionException e) {
			log.error("connection failed: MpdConnectionException: " + e.getMessage());
			throw new MpdException(e.getMessage(), e);
		}
	}
	
	public MPDSong findSong(String artist, String title, String album) throws MpdException {
		ArrayList<MPDSong> artistTitleResults = new ArrayList<MPDSong>();
		try {
			log.trace("searching for artist " + artist);
			Collection<MPDSong> artists = mpdDatabase.searchArtist(new MPDArtist(artist));
			log.debug("found " + artists.size() + " songs for artist " + artist);
			
			log.trace("searching for title " + title);
			Collection<MPDSong> titles = mpdDatabase.searchTitle(title);
			log.debug("found " + titles.size() + " songs for title " + title);
			
			for (MPDSong songByArtist : artists) {
				for (MPDSong songByTitle : titles) {
					if (songByArtist.equals(songByTitle)) {
//						log.debug("match: " + songByTitle.getFile());
						artistTitleResults.add(songByTitle);
					}
				}
			}
			log.debug("found " + artistTitleResults.size() + " results for " + artist + " and " + title);

			if (artistTitleResults.size() == 0) {
				log.warn("no match in database for " + artist + " - " + title);
				return null;
			}
			
			if (album != null) {
				log.trace("searching for song from album " + album);
				MPDSong lowestDistanceSong = null;
				int lowestDistance = 0;
				for (MPDSong song: artistTitleResults) {
					int distance = Integer.MAX_VALUE;
					
					if (song.getAlbum() != null) {
						String songsAlbum = song.getAlbum().getName();
						distance = LevenshteinDistance.levenshtein(album, songsAlbum);
					}

					if (distance < lowestDistance || lowestDistanceSong == null) {
						log.trace("new best song: " + distance + " " + song.getFile());
						lowestDistance = distance;
						lowestDistanceSong = song;
					}
				}
				
				log.debug("our match is: " + lowestDistanceSong.getFile());
				return lowestDistanceSong;
				
			} else {
				log.debug("no album given. returning a random song out of our results");
				return artistTitleResults.get(new Random().nextInt(artistTitleResults.size()));
			}
			
			
		} catch (MPDDatabaseException e) {
			log.error("MPDDatabaseException: " + e.getMessage());
			throw new MpdException(e.getMessage(), e);
		} catch (MPDConnectionException e) {
			log.error("MPDConnectionException: " + e.getMessage());
			throw new MpdException(e.getMessage(), e);
		}
	}
	
	public void addSongToPlaylist(MPDSong song) throws MpdException {
		log.info("adding song to playist: " + song.getFile());
		try {
			mpd.getMPDPlaylist().addSong(song);
		} catch (MPDPlaylistException e) {
			log.error("MPDPlaylistException: " + e.getMessage());
			throw new MpdException(e.getMessage(), e);
		} catch (MPDConnectionException e) {
			log.error("MPDConnectionException: " + e.getMessage());
			throw new MpdException(e.getMessage(), e);
		}
	}

	@Override
	public String toString() {
		return "MpdConnection [mpdHost=" + mpdHost + ", mpdPort=" + mpdPort
		+ ", mpdPassword=" + mpdPassword + "]";
	}
}
